package com.lazyframework.security.web.authentication.filter;

import com.lazyframework.security.web.SecurityContextHolder;
import com.lazyframework.security.web.authentication.AuthorizationType;
import com.lazyframework.security.web.authentication.token.Authentication;
import com.lazyframework.security.web.authentication.token.JwtAuthenticationToken;
import com.lazyframework.security.web.exception.AuthenticationException;
import com.lazyframework.security.web.exception.JwtAuthenticationException;
import com.lazyframework.security.web.authentication.SecurityResponseStatus;
import com.lazyframework.commons.support.ResponseModels;
import io.jsonwebtoken.*;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class JwtAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private AuthorizationType authorizationType;

    private static String AUTHORIZATION = "Authorization";

    @Override
    protected boolean requires(HttpServletRequest request) {
        String authorization = request.getHeader(AUTHORIZATION);
        return StringUtils.hasText(authorization) && authorization.startsWith(authorizationType.prefix());
    }

    @Override
    protected Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
        String authorization = request.getHeader(AUTHORIZATION);
        String authorizationWithoutPrefix = authorization.replace(authorizationType.prefix(), "");

        JwtAuthenticationToken token = new JwtAuthenticationToken(authorizationWithoutPrefix);

        return authenticationManager().authenticate(token);
    }

    public void setAuthorizationType(AuthorizationType authorizationType) {
        this.authorizationType = authorizationType;
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletResponse response, AuthenticationException ae)
            throws IOException {
        JwtException je = ((JwtAuthenticationException) ae).getException();
        if (je instanceof MalformedJwtException) {
            ResponseModels.print(response, SecurityResponseStatus.MALFORMED_JWT);
        } else if (je instanceof UnsupportedJwtException) {
            ResponseModels.print(response, SecurityResponseStatus.UNSUPPORTED_JWT);
        } else if (je instanceof SignatureException) {
            ResponseModels.print(response, SecurityResponseStatus.JWT_SIGNATURE_ERROR);
        } else if (je instanceof ExpiredJwtException) {
            ResponseModels.print(response, SecurityResponseStatus.EXPIRED_JWT);
        } else {
            throw je;
        }
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                            Authentication authentication) {
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }
}
